Completed
Push — master ( e4b8ca...a9bd47 )
by Sander
01:15
created

background.constructor   B

Complexity

Conditions 1
Paths 2

Size

Total Lines 624

Duplication

Lines 0
Ratio 0 %

Importance

Changes 8
Bugs 1 Features 0
Metric Value
cc 1
c 8
b 1
f 0
nc 2
nop 0
dl 0
loc 624
rs 8.2857

59 Functions

Rating   Name   Duplication   Size   Complexity  
A background.js ➔ isMasterPasswordValid 0 9 2
A background.js ➔ setMasterPassword 0 17 4
A background.js ➔ getMasterPasswordSet 0 3 1
A background.js ➔ getRuntimeSettings 0 3 1
A background.js ➔ passToParent 0 4 1
A API.runtime.onConnect.addListener 0 10 1
A background.js ➔ ... ➔ PAPI.updateCredential 0 7 2
B background.js ➔ searchCredential 0 21 5
A background.js ➔ ... ➔ API.tabs.then 0 5 2
A storage.then 0 9 2
A background.js ➔ saveCredential 0 21 4
A background.js ➔ getCredentialByGuid 0 8 3
A background.js ➔ ... ➔ PAPI.updateCredential 0 5 2
A background.js ➔ ... ➔ API.tabs.then 0 4 1
A background.js ➔ updateCredentialUrlDoorhanger 0 12 1
A API.tabs.onActivated.addListener 0 7 2
A background.js ➔ saveMinedCallback 0 7 1
A storage.error 0 5 2
A API.runtime.onConnect.addListener 0 6 2
A background.js ➔ getSettings 0 56 1
A background.js ➔ updateCredentialUrl 0 5 1
A background.js ➔ getCredentialForHTTPAuth 0 3 1
A background.js ➔ isVaultKeySet 0 3 1
A background.js ➔ displayLogoutIcons 0 21 2
A background.js ➔ ... ➔ storage.then 0 3 1
B background.js ➔ minedForm 0 30 4
A background.js ➔ ... ➔ setInterval 0 3 1
C background.js ➔ ... ➔ PAPI.getVault 0 28 7
A background.js ➔ ... ➔ PAPI.createCredential 0 5 1
A background.js ➔ updateTabsIcon 0 8 1
B background.js ➔ createIconForTab 0 25 4
A background.js ➔ getSetting 0 3 1
A background.js ➔ ... ➔ PAPI.createCredential 0 5 1
A background.js ➔ ... ➔ PAPI.createCredential 0 3 1
A background.js ➔ getMinedData 0 19 4
A background.js ➔ ignoreSite 0 10 3
B background.js ➔ saveMined 0 37 5
A API.runtime.onMessage.addListener 0 14 4
B background.js ➔ getCredentialsByUrl 0 18 9
A background.js ➔ ... ➔ API.tabs.then 0 2 1
A background.js ➔ closeSetupTab 0 7 1
A background.js ➔ ... ➔ API.tabs.then 0 10 1
B background.js ➔ getCredentials 0 35 2
A API.tabs.onActivated.addListener 0 9 1
A background.js ➔ ... ➔ API.tabs.then 0 2 1
C background.js ➔ ... ➔ storage.then 0 53 13
A background.js ➔ clearMined 0 3 1
A background.js ➔ injectCreateCredential 0 13 1
A background.js ➔ getDoorhangerData 0 3 1
A background.js ➔ ... ➔ API.tabs.then 0 5 1
A background.js ➔ isAutoFillEnabled 0 6 2
A background.js ➔ ... ➔ _self.settings.ignored_sites.filter 0 3 1
B background.js ➔ saveSettings 0 26 4
A background.js ➔ getActiveTab 0 7 1
A API.tabs.onUpdated.addListener 0 7 2
A background.js ➔ ... ➔ API.tabs.then 0 17 2
A background.js ➔ ... ➔ API.tabs.then 0 6 2
A background.js ➔ setDoorhangerData 0 3 1
A background.js ➔ ... ➔ API.tabs.then 0 2 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
/* global API */
2
3
var background = (function () {
4
    var storage = new API.Storage();
5
    var _self = this;
6
    var _window = {};
7
8
9
    API.runtime.onConnect.addListener(function (port) {
10
11
        port.onMessage.addListener(function (msg) {
12
            if (msg === 'credential_amount') {
13
                port.postMessage('credential_amount:' + local_credentials.length);
14
            }
15
16
        });
17
18
    });
19
20
    var master_password = null;
21
22
    function getMasterPasswordSet() {
23
        return (master_password !== null);
24
    }
25
26
    _self.getMasterPasswordSet = getMasterPasswordSet;
27
28
    function setMasterPassword(opts) {
29
        master_password = opts.password;
30
        if (opts.hasOwnProperty('savePassword') && opts.savePassword === true) {
31
            // Save the password in plain text on user request.
32
            // No secure local storage is available :/
33
            storage.set('master_password', opts.password);
34
        } else {
35
            storage.set('master_password', null);
36
        }
37
38
        if (opts.password) {
39
            getSettings();
40
        } else {
41
            displayLogoutIcons();
42
        }
43
44
    }
45
46
    _self.setMasterPassword = setMasterPassword;
47
48
49
    var testMasterPasswordAgainst;
50
51
    function isMasterPasswordValid(password) {
52
        //return true;
53
        try {
54
            PAPI.decryptString(testMasterPasswordAgainst, password);
55
            return true;
56
        } catch (e) {
57
            return false;
58
        }
59
    }
60
61
    _self.isMasterPasswordValid = isMasterPasswordValid;
62
63
64
    var local_credentials = [];
65
    var local_vault = [];
66
    var encryptedFieldSettings = ['default_vault', 'nextcloud_host', 'nextcloud_username', 'nextcloud_password', 'vault_password'];
67
    _self.settings = {};
68
    _self.ticker = null;
69
    _self.running = false;
70
    function getSettings() {
71
72
        storage.get('settings').then(function (_settings) {
73
74
            if ((!_settings || !_settings.hasOwnProperty('nextcloud_host')) && !master_password) {
75
                API.tabs.create({
76
                    url: '/html/browser_action/browser_action.html'
77
                });
78
79
                return;
80
            }
81
82
            if (!master_password && _settings.hasOwnProperty('nextcloud_username') && _settings.hasOwnProperty('vault_password')) {
83
                _self.settings.isInstalled = 1;
84
                testMasterPasswordAgainst = _settings.nextcloud_username;
85
                return;
86
            }
87
88
            for (var i = 0; i < encryptedFieldSettings.length; i++) {
89
                var field = encryptedFieldSettings[i];
90
                _settings[field] = JSON.parse(PAPI.decryptString(_settings[field], master_password));
91
            }
92
93
94
            _self.settings = _settings;
95
96
            if (!_self.settings.hasOwnProperty('ignored_sites')) {
97
                _self.settings.ignored_sites = [];
98
            }
99
100
            if (!_self.settings.hasOwnProperty('disable_browser_autofill')) {
101
                _self.settings.disable_browser_autofill = true;
102
            }
103
104
105
            PAPI.host = _settings.nextcloud_host;
106
            PAPI.username = _settings.nextcloud_username;
107
            PAPI.password = _settings.nextcloud_password;
108
            if (!_settings.vault_password) {
109
                return;
110
            }
111
            if (PAPI.credentialsSet()) {
112
                getCredentials();
113
                if (_self.running) {
114
                    clearInterval(_self.ticker);
115
                }
116
117
                _self.running = true;
118
                _self.ticker = setInterval(function () {
119
                    getCredentials();
120
                }, _self.settings.refreshTime * 1000);
121
            } else {
122
                console.log('Login details are missing!');
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
123
            }
124
        });
125
    }
126
127
    _self.getSettings = getSettings;
128
129
    function getRuntimeSettings() {
130
        return _self.settings;
131
    }
132
133
    _self.getRuntimeSettings = getRuntimeSettings;
134
135
    function getSetting(name) {
136
        return _self.settings[name];
137
    }
138
139
    _self.getSetting = getSetting;
140
141
    function saveSettings(settings, cb) {
0 ignored issues
show
Unused Code introduced by
The parameter cb is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
142
        for (var i = 0; i < encryptedFieldSettings.length; i++) {
143
            var field = encryptedFieldSettings[i];
144
            settings[field] = PAPI.encryptString(JSON.stringify(settings[field]), master_password);
145
        }
146
        PAPI.host = settings.nextcloud_host;
147
        PAPI.username = settings.nextcloud_username;
148
        PAPI.password = settings.nextcloud_password;
149
150
        if (!settings.hasOwnProperty('ignored_sites')) {
151
            settings.ignored_sites = [];
152
        }
153
154
        if (!settings.hasOwnProperty('disable_browser_autofill')) {
155
            settings.disable_browser_autofill = true;
156
        }
157
158
        //window.settings contains the run-time settings
159
        _self.settings = settings;
160
161
162
        storage.set('settings', settings).then(function () {
163
            getSettings();
164
        });
165
166
    }
167
168
    _self.saveSettings = saveSettings;
169
170
171
    function getCredentials() {
172
        if (!master_password) {
173
            return;
174
        }
175
        //console.log('Loading vault with the following settings: ', settings);
176
        var tmpList = [];
177
        PAPI.getVault(_self.settings.default_vault.guid, function (vault) {
178
            if (vault.hasOwnProperty('error')) {
179
                return;
180
            }
181
            var _credentials = vault.credentials;
182
            for (var i = 0; i < _credentials.length; i++) {
183
                var key = _self.settings.vault_password;
184
                var credential = _credentials[i];
185
                if (credential.hidden === 1) {
186
                    continue;
187
                }
188
                var usedKey = key;
189
                //Shared credentials are not implemented yet
190
                if (credential.hasOwnProperty('shared_key') && credential.shared_key) {
191
                    usedKey = PAPI.decryptString(credential.shared_key, key);
192
193
                }
194
                credential = PAPI.decryptCredential(credential, usedKey);
195
                if (credential.delete_time === 0) {
196
                    tmpList.push(credential);
197
                }
198
199
            }
200
            delete vault.credentials;
201
            local_vault = vault;
202
            local_credentials = tmpList;
203
            updateTabsIcon();
204
        });
205
    }
206
207
    _self.getCredentials = getCredentials;
208
209
    function getCredentialsByUrl(_url, sender) {
0 ignored issues
show
Unused Code introduced by
The parameter sender is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
210
        if (!master_password) {
211
            return [];
212
        }
213
        if (!_url || _url === '') {
214
            return [];
215
        }
216
        var url = processURL(_url, _self.settings.ignoreProtocol, _self.settings.ignoreSubdomain, _self.settings.ignorePath, _self.settings.ignorePort);
217
        var found_list = [];
218
        for (var i = 0; i < local_credentials.length; i++) {
219
            if (local_credentials[i].url && local_credentials[i].username && local_credentials[i].password) {
220
                if (local_credentials[i].url.indexOf(url) !== -1) {
221
                    found_list.push(local_credentials[i]);
222
                }
223
            }
224
        }
225
        return found_list;
226
    }
227
228
    _self.getCredentialsByUrl = getCredentialsByUrl;
229
230
231
    function saveCredential(credential) {
232
        if (!credential.credential_id) {
233
            PAPI.createCredential(credential, _self.settings.vault_password, function (createdCredential) {
234
                local_credentials.push(createdCredential);
235
            });
236
        } else {
237
            var credential_index;
238
            for (var i = 0; i < local_credentials.length; i++) {
239
                if (local_credentials[i].guid === credential.guid) {
240
                    credential_index = i;
241
                    break;
242
                }
243
            }
244
245
            PAPI.updateCredential(credential, _self.settings.vault_password, function (updatedCredential) {
246
                if (credential_index) {
247
                    local_credentials[credential_index] = updatedCredential;
248
                }
249
            });
250
        }
251
    }
252
253
    _self.saveCredential = saveCredential;
254
255
    function getCredentialByGuid(guid) {
256
        for (var i = 0; i < local_credentials.length; i++) {
257
            var credential = local_credentials[i];
258
            if (credential.guid === guid) {
259
                return credential;
260
            }
261
        }
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
262
    }
263
264
    _self.getCredentialByGuid = getCredentialByGuid;
265
266
    function getCredentialForHTTPAuth(req) {
267
        return getCredentialsByUrl(req.url)[0];
268
    }
269
270
    _window.getCredentialForHTTPAuth = getCredentialForHTTPAuth;
271
272
    var mined_data = [];
273
274
    function minedForm(data, sender) {
275
        var url = sender.url;
276
        var existingLogins = getCredentialsByUrl(sender.url);
277
        var title = API.i18n.getMessage('detected_new_login') + ':';
278
        var minedMatchingID = null;
279
        for (var j = 0; j < existingLogins.length; j++) {
280
            var login = existingLogins[j];
281
            if (login.username === data.username) {
282
                if (login.password !== data.password) {
283
                    minedMatchingID = login.guid;
284
                    title = API.i18n.getMessage('detected_changed_login') + ':';
285
                }
286
                else {
287
                    //console.log('No changes detected');
288
                    delete mined_data[sender.tab.id];
289
                    return;
290
                }
291
            }
292
        }
293
        mined_data[sender.tab.id] = {
294
            title: title,
295
            url: url,
296
            username: data.username,
297
            password: data.password,
298
            label: sender.title,
299
            guid: minedMatchingID
300
        };
301
302
        //console.log('Done mining, ', mined_data, sender.tab.id);
303
    }
304
305
    _self.minedForm = minedForm;
306
307
    function getMinedData(args, sender) {
308
        //console.log('Fecthing  mined data for tab id', sender.tab.id)
309
        var senderUrl = sender.tab.url;
310
        var site = processURL(senderUrl, _self.settings.ignoreProtocol, _self.settings.ignoreSubdomain, _self.settings.ignorePath, _self.settings.ignorePort);
311
        if (!_self.settings) {
312
            return null;
313
        }
314
        if (!_self.settings.hasOwnProperty('ignored_sites')) {
315
            return mined_data[sender.tab.id];
316
        }
317
        var matches = _self.settings.ignored_sites.filter(function (item) {
318
            return typeof item === 'string' && site.indexOf(item) > -1;
319
        });
320
321
        if (matches.length !== 0) {
322
            return null;
323
        }
324
        return mined_data[sender.tab.id];
325
    }
326
327
    _self.getMinedData = getMinedData;
328
329
    function clearMined(args, sender) {
330
        delete mined_data[sender.tab.id];
331
    }
332
333
    _self.clearMined = clearMined;
334
335
    function saveMinedCallback(args) {
336
        createIconForTab(args.sender.tab);
337
        API.tabs.query({active: true, currentWindow: true}).then(function (tabs) {
338
            API.tabs.sendMessage(args.sender.tab.id, {method: "minedLoginSaved", args: args}).then(function (response) {
0 ignored issues
show
Unused Code introduced by
The parameter response is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
339
            });
340
        });
341
    }
342
343
    function ignoreSite(_url) {
344
        if (!_self.settings.hasOwnProperty('ignored_sites')) {
345
            _self.settings.ignored_sites = [];
346
        }
347
        var site = processURL(_url, _self.settings.ignoreProtocol, _self.settings.ignoreSubdomain, _self.settings.ignorePath, _self.settings.ignorePort);
348
        if (_self.settings.ignored_sites.indexOf(site) === -1) {
349
            _self.settings.ignored_sites.push(site);
350
            saveSettings(_self.settings);
351
        }
352
    }
353
354
    _self.ignoreSite = ignoreSite;
355
356
    function passToParent(args, sender) {
357
        API.tabs.sendMessage(sender.tab.id, {method: args.injectMethod, args: args.args}).then(function (response) {
0 ignored issues
show
Unused Code introduced by
The parameter response is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
358
        });
359
    }
360
361
    _self.passToParent = passToParent;
362
363
    function getActiveTab(opt) {
364
        API.tabs.query({active: true, currentWindow: true}).then(function (tabs) {
365
            var tab = tabs[0];
366
            API.tabs.sendMessage(tab.id, {method: opt.returnFn, args: tab}).then(function (response) {
0 ignored issues
show
Unused Code introduced by
The parameter response is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
367
            });
368
        });
369
    }
370
371
    _self.getActiveTab = getActiveTab;
372
373
    function updateCredentialUrlDoorhanger(login) {
374
        API.tabs.query({active: true, currentWindow: true}).then(function (tabs) {
375
            var tab = tabs[0];
376
            var data = login;
377
            data.url = tab.url;
378
            data.title = API.i18n.getMessage('detected_changed_url') + ':';
379
            API.tabs.sendMessage(tab.id, {
380
                method: 'showUrlUpdateDoorhanger',
381
                args: {data: data}
382
            });
383
        });
384
    }
385
386
    _self.updateCredentialUrlDoorhanger = updateCredentialUrlDoorhanger;
387
388
    function updateCredentialUrl(data, sender) {
389
        mined_data[sender.tab.id] = data;
390
        saveMined({}, sender);
391
392
    }
393
394
    _self.updateCredentialUrl = updateCredentialUrl;
395
396
    function saveMined(args, sender) {
397
        var data = mined_data[sender.tab.id];
398
        var credential,
399
            credential_index;
400
401
        if (data.guid === null) {
402
            credential = PAPI.newCredential();
403
        } else {
404
            for (var i = 0; i < local_credentials.length; i++) {
405
                if (local_credentials[i].guid === data.guid) {
406
                    credential = local_credentials[i];
407
                    credential_index = i;
408
                    break;
409
                }
410
            }
411
        }
412
        credential.username = data.username;
0 ignored issues
show
Bug introduced by
The variable credential seems to not be initialized for all possible execution paths.
Loading history...
413
        credential.password = data.password;
414
        credential.url = sender.tab.url;
415
        if (credential.guid !== null) {
416
            PAPI.updateCredential(credential, _self.settings.vault_password, function (updatedCredential) {
417
                if (credential_index) {
418
                    local_credentials[credential_index] = updatedCredential;
419
                }
420
                saveMinedCallback({credential: credential, updated: true, sender: sender});
0 ignored issues
show
Bug introduced by
The variable credential seems to not be initialized for all possible execution paths.
Loading history...
421
                delete mined_data[sender.tab.id];
422
            });
423
        } else {
424
            credential.label = sender.tab.title;
425
            credential.vault_id = local_vault.vault_id;
426
            PAPI.createCredential(credential, _self.settings.vault_password, function (createdCredential) {
427
                saveMinedCallback({credential: credential, updated: false, sender: sender});
0 ignored issues
show
Bug introduced by
The variable credential seems to not be initialized for all possible execution paths.
Loading history...
428
                local_credentials.push(createdCredential);
429
                delete mined_data[sender.tab.id];
430
            });
431
        }
432
    }
433
434
    _self.saveMined = saveMined;
435
436
    function searchCredential(searchText) {
437
        searchText = searchText.toLowerCase();
438
        var searchFields = ['label', 'username', 'email', 'url', 'description'];
439
        var results = [];
440
        for (var i = 0; i < local_credentials.length; i++) {
441
            var credential = local_credentials[i];
442
            for (var f = 0; f < searchFields.length; f++) {
443
                var field = searchFields[f];
444
                if(!credential[field]){
445
                    continue;
446
                }
447
448
                var field_value = credential[field].toLowerCase();
449
                if (field_value.indexOf(searchText) !== -1) {
450
                    results.push(credential);
451
                    break;
452
                }
453
            }
454
        }
455
        return results;
456
    }
457
458
    _self.searchCredential = searchCredential;
459
460
461
    function injectCreateCredential(args, sender) {
462
        var credential = PAPI.newCredential();
463
        credential.label = args.label;
464
        credential.username = args.username;
465
        credential.password = args.password;
466
        credential.vault_id = local_vault.vault_id;
467
        credential.url = sender.tab.url;
468
        PAPI.createCredential(credential, _self.settings.vault_password, function (createdCredential) {
469
            saveMinedCallback({credential: credential, updated: false, sender: sender, selfAdded: true});
470
            local_credentials.push(createdCredential);
471
472
        });
473
    }
474
475
    self.injectCreateCredential = injectCreateCredential;
0 ignored issues
show
Bug introduced by
The variable self seems to be never declared. If this is a global, consider adding a /** global: self */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
476
477
    function isVaultKeySet() {
478
        return (_self.settings.vault_password !== null);
479
    }
480
481
    _self.isVaultKeySet = isVaultKeySet;
482
483
    function isAutoFillEnabled() {
484
        if (!_self.settings.hasOwnProperty('disableAutoFill')) {
485
            return true;
486
        }
487
        return (_self.settings.disableAutoFill === false);
488
    }
489
490
    _self.isAutoFillEnabled = isAutoFillEnabled;
491
492
    var doorhangerData = null;
493
494
    function setDoorhangerData(data) {
495
        doorhangerData = data;
496
    }
497
498
    _self.setDoorhangerData = setDoorhangerData;
499
500
    function getDoorhangerData() {
501
        return doorhangerData;
502
    }
503
504
    _self.getDoorhangerData = getDoorhangerData;
505
506
    function closeSetupTab() {
507
        API.tabs.query({url: 'chrome-extension://'+ API.runtime.id +'/html/browser_action/browser_action.html'}).then(function (tabs) {
508
           if(tabs) {
509
               API.tabs.remove(tabs[0].id);
510
           }
511
        });
512
    }
513
    _self.closeSetupTab = closeSetupTab;
514
515
    API.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
516
517
        if (!msg || !msg.hasOwnProperty('method')) {
518
            return;
519
        }
520
        var result = false;
521
        if (_self[msg.method]) {
522
            result = _self[msg.method](msg.args, sender);
523
        } else {
524
            console.warn('[NOT FOUND] Method call', msg.method, 'args: ', msg.args);
525
        }
526
527
        sendResponse(result);
528
    });
529
530
    var defaultColor = '#0082c9';
531
532
    function createIconForTab(tab) {
533
        if (!master_password) {
534
            return;
535
        }
536
        var tabUrl = tab.url;
537
        var logins = getCredentialsByUrl(tabUrl);
538
        if (tab.active) {
539
            window.contextMenu.setContextItems(logins);
540
        }
541
        var credentialAmount = logins.length;
542
        API.browserAction.setBadgeText({
543
            text: credentialAmount.toString(),
544
            tabId: tab.id
545
        });
546
        API.browserAction.setBadgeBackgroundColor({
547
            color: defaultColor,
548
            tabId: tab.id
549
        });
550
551
        var plural = (credentialAmount === 1) ? API.i18n.getMessage('credential') : API.i18n.getMessage('credentials');
552
        API.browserAction.setTitle({
553
            title: API.i18n.getMessage('browser_action_title_login', [credentialAmount.toString(), plural.toString()]),
554
            tabId: tab.id
555
        });
556
    }
557
558
    function displayLogoutIcons() {
559
        if (_self.settings) {
560
            API.tabs.query({}).then(function (tabs) {
561
                for (var t = 0; t < tabs.length; t++) {
562
                    var tab = tabs[t];
563
                    API.browserAction.setBadgeText({
564
                        text: '🔑',
565
                        tabId: tab.id
566
                    });
567
                    API.browserAction.setBadgeBackgroundColor({
568
                        color: '#ff0000',
569
                        tabId: tab.id
570
                    });
571
                    API.browserAction.setTitle({
572
                        title: API.i18n.getMessage('browser_action_title_locked'),
573
                        tabId: tab.id
574
                    });
575
                }
576
            });
577
        }
578
    }
579
580
    function updateTabsIcon() {
581
        API.tabs.query({}).then(function (tabs) {
582
            for (var t = 0; t < tabs.length; t++) {
583
                var tab = tabs[t];
584
                createIconForTab(tab);
585
            }
586
        });
587
    }
588
589
590
    API.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
591
        if (master_password) {
592
            createIconForTab(tab);
593
        } else {
594
            displayLogoutIcons();
595
        }
596
    });
597
598
    API.tabs.onActivated.addListener(function () {
599
        API.tabs.query({active: true, currentWindow: true}).then(function (tabs) {
600
            if (master_password) {
601
                createIconForTab(tabs[0]);
602
            } else {
603
                displayLogoutIcons();
604
            }
605
        });
606
    });
607
608
    displayLogoutIcons();
609
610
611
612
    storage.get('master_password').then(function (password) {
613
        if (password) {
614
            master_password = password;
615
            API.api.browserAction.setBadgeBackgroundColor({
616
                color: defaultColor
617
            });
618
        }
619
        getSettings();
620
    }).error(function (error) {
621
        if (error === "Data not found") {
622
            getSettings();
623
        }
624
    });
625
    return _window;
626
}());
627
628